﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.IO;

namespace Samples
{
    public abstract class MenuItem : IDisposable
    {
        public string Name { get; set; }
        public MenuFolder Parent { get; set; }
        protected MenuItem(string name)
        {
            Name = name;
            Parent = null;
        }

        #region IDisposable Members
        public abstract void Dispose();
        #endregion
    }
    public class MenuFolder : MenuItem
    {
        private List<MenuItem> childs;
        public MenuFolder(string name)
            : base(name)
        {
            childs = new List<MenuItem>();
        }

        public int NumChilds { get { return childs.Count; } }

        public void Add(MenuItem item)
        {
            childs.Add(item);
            item.Parent = this;
        }
        public MenuItem this[int index]
        {
            get { return childs[index]; }
        }

        #region IDisposable Members

        public override void Dispose()
        {
            if (childs != null)
            {
                foreach (MenuItem m in childs)
                {
                    m.Dispose();
                }
                childs.Clear();
            }
            childs = null;
        }

        #endregion
    }
    public class MenuApp : MenuItem
    {
        public OdeDemo Demo { get; private set; }
        public MenuApp(string name, OdeDemo demo)
            : base(name)
        {
            Demo = demo;
        }

        public override void Dispose()
        {
        }
    }

    public class Menu : IDisposable
    {
        const string FileName = "LaseDemo.txt";
        private Color SelectedColor = new Color(143, 143, 143);
        private Color DeselectedColor = new Color(161, 103, 41);

        public DemoFramework FrameWork { get; private set; }
        private SpriteBatch sprite;
        private SpriteFont font;
        private Texture2D background;
        private Texture2D AppTex;
        private Texture2D FolderCloseTex;
        private Texture2D FolderOpenTex;
        public MenuFolder Root { get; private set; }

        private MenuFolder currenyItem = null;
        private int index = 0;
        private int preIndex = 0;
        private bool isUpDown = false;
        private bool isDownDown = false;
        private bool isEnterDown = false;
        private bool isBackDown = false;

        const float MAXOFFSET = 20;
        const float OFFSETSPEED = 0.2f;
        private float offsetCurrent = 0;
        private float offsetPrevious = 0;

        Stack<MenuFolder> drawParentsStack = new Stack<MenuFolder>();


        public Menu(DemoFramework frameWork)
        {
            FrameWork = frameWork;
            Root = new MenuFolder("Ode Demos");
            currenyItem = Root;
        }

        internal void GoToLastDemo()
        {
            if (File.Exists(FileName))
            {
                FileStream file = new FileStream(FileName, FileMode.Open, FileAccess.Read);
                StreamReader reader = new StreamReader(file);

                string line = reader.ReadLine();
                string[] folders = line.Split('|');
                if (folders != null && folders.Length > 0)
                {
                    for (int i = 0; i < folders.Length; i++)
                    {
                        GoToChile(folders[i]);
                    }
                    line = reader.ReadLine();
                    int.TryParse(line, out index);
                    preIndex = index;
                    offsetPrevious = offsetCurrent = 0;
                }

                reader.Close();
                file.Close();
            }

        }
        internal void SaveLastDemo()
        {
            MenuFolder folder = currenyItem;
            List<string> list = new List<string>();
            while (folder != null)
            {
                list.Add(folder.Name);
                folder = folder.Parent;
            }
            if (list.Count > 0)
            {
                if (File.Exists(FileName))
                    File.Delete(FileName);
                FileStream file = new FileStream(FileName, FileMode.Create, FileAccess.Write);
                StreamWriter writer = new StreamWriter(file);
                list.Reverse();

                for (int i = 0; i < list.Count; i++)
                {
                    writer.Write(list[i]);
                    writer.Write("|");
                }
                writer.WriteLine();
                writer.WriteLine(index);
                writer.Close();
                file.Close();
            }
            list.Clear();
            folder = null;
        }

        private void GoToParent()
        {
            if (currenyItem.Parent != null)
            {
                currenyItem = currenyItem.Parent;
                preIndex = index = 0;
                offsetPrevious = offsetCurrent = 0;
            }
        }
        private void GoToChile(int index)
        {
            if (currenyItem.NumChilds > 0)
            {
                if (currenyItem[index] is MenuFolder)
                {
                    currenyItem = currenyItem[index] as MenuFolder;
                    preIndex = this.index = 0;
                    offsetPrevious = offsetCurrent = 0;
                }
                else
                    Execute(currenyItem[index] as MenuApp);
            }
        }
        private void GoToChile(string name)
        {
            if (currenyItem.NumChilds > 0)
            {
                for (int i = 0; i < currenyItem.NumChilds; i++)
                {
                    if (currenyItem[i] is MenuFolder && currenyItem[i].Name == name)
                    {
                        currenyItem = currenyItem[i] as MenuFolder;
                        break;
                    }
                }
            }
        }

        private void Execute(MenuApp menuApp)
        {
            FrameWork.Demo = menuApp.Demo;
        }


        public void Initialize()
        {
            sprite = new SpriteBatch(FrameWork.GraphicsDevice);
            font = FrameWork.Content.Load<SpriteFont>("Times");
            background = FrameWork.Content.Load<Texture2D>("BackGround");
            FolderCloseTex = FrameWork.Content.Load<Texture2D>("FolderClose");
            FolderOpenTex = FrameWork.Content.Load<Texture2D>("FolderOpen");
            AppTex = FrameWork.Content.Load<Texture2D>("App");
        }

        public void Update(GameTime gameTime)
        {

            if (FrameWork.Keyboard.IsKeyDown(Keys.Up))
            {
                if (isUpDown == false)
                {
                    preIndex = index;
                    index--;
                    if (index < 0)
                        index = currenyItem.NumChilds - 1;
                    else
                    {
                        offsetPrevious = offsetCurrent;
                        offsetCurrent = 0;
                    }
                    isUpDown = true;
                    return;
                }
            }
            else
            {
                isUpDown = false;
            }
            if (FrameWork.Keyboard.IsKeyDown(Keys.Down))
            {
                if (isDownDown == false)
                {
                    preIndex = index;
                    index++;
                    if (index == currenyItem.NumChilds)
                        index = 0;
                    else
                    {
                        offsetPrevious = offsetCurrent;
                        offsetCurrent = 0;
                    }
                    isDownDown = true;
                    return;
                }
            }
            else
            {
                isDownDown = false;
            }
            if (FrameWork.Keyboard.IsKeyDown(Keys.Enter))
            {
                if (isEnterDown == false)
                {
                    GoToChile(index);
                    isEnterDown = true;
                    return;
                }
            }
            else
            {
                isEnterDown = false;
            }
            if (FrameWork.Keyboard.IsKeyDown(Keys.Back))
            {
                if (isBackDown == false)
                {
                    GoToParent();
                    isBackDown = true;
                    return;
                }
            }
            else
            {
                isBackDown = false;
            }
        }
        public void Draw(GameTime gameTime)
        {
            if (index >= currenyItem.NumChilds)
                preIndex = index = 0;
            float off = OFFSETSPEED * gameTime.ElapsedGameTime.Milliseconds;
            offsetPrevious -= off;
            offsetCurrent += off;
            if (offsetPrevious < 0)
            {
                offsetPrevious = 0;
                preIndex = index;
            }
            offsetCurrent = offsetCurrent > MAXOFFSET ? MAXOFFSET : offsetCurrent;

            sprite.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            sprite.Draw(background, new Rectangle(0, 0, FrameWork.GraphicsDevice.Viewport.Width, FrameWork.GraphicsDevice.Viewport.Height), Color.White);
            if (currenyItem != null && currenyItem is MenuFolder)
            {
                Vector2 pos = new Vector2(20, 20);
                MenuFolder folder = currenyItem as MenuFolder;
                MenuFolder parent = folder.Parent;
                while (parent != null)
                {
                    drawParentsStack.Push(parent);
                    parent = parent.Parent;
                }
                while (drawParentsStack.Count > 0)
                {
                    parent = drawParentsStack.Pop();
                    DrawItem(parent, pos, true, false, false);
                    pos.X += 30;
                    pos.Y += 30;
                }

                DrawItem(folder, pos, true, false, false);
                pos.X += 30;
                pos.Y += 30;
                for (int i = 0; i < folder.NumChilds; i++)
                {
                    DrawItem(folder[i], pos, false, i == index, i == preIndex && index != preIndex);
                    pos.Y += 30;
                }
            }
            sprite.End();
        }

        private void DrawItem(MenuItem item, Vector2 point, bool open, bool selected, bool preSelected)
        {
            int off = (int)((selected ? offsetCurrent : 0) + (preSelected ? offsetPrevious : 0));
            if (item is MenuFolder)
            {
                sprite.Draw(open ? FolderOpenTex : FolderCloseTex, new Rectangle((int)point.X + off, (int)point.Y, 32, 32), Color.White);
                point.X += 40 + off;
                sprite.DrawString(font, item.Name, point, selected ? SelectedColor : DeselectedColor);
            }
            else if (item is MenuApp)
            {
                sprite.Draw(AppTex, new Rectangle((int)point.X + off, (int)point.Y, 32, 32), Color.White);
                point.X += 40 + off;
                sprite.DrawString(font, item.Name, point, selected ? SelectedColor : DeselectedColor);
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (Root != null)
                Root.Dispose();
            Root = null;
            if (sprite != null)
                sprite.Dispose();
            sprite = null;
            if (background != null)
                background.Dispose();
            background = null;
        }
        #endregion
    }
}
